package docbookarchivemanager;

import docbookarchivemanager.utils.DocbookFile;
import docbookarchivemanager.commands.Command;
import docbookarchivemanager.commands.CommandHandler;
import docbookarchivemanager.converter.Converter;
import docbookarchivemanager.converter.elements.Data;
import docbookarchivemanager.transformer.Transformere;
import docbookarchivemanager.utils.DomManager;
import docbookarchivemanager.utils.FileManager;
import docbookarchivemanager.utils.StringHelper;
import docbookarchivemanager.utils.Stylesheet;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import org.xml.sax.SAXException;

/**
 *
 * @author Jakub Hrachovec
 */
public class StartupManager {

    private static final File startFolder = new File(".");
    private static String globalNameOfFile;
    private static File globalParentFolder;
    private static File globalOutputFolder;
    private static File tempFileDownloads;

    private static File outputFile = null;

    /**
     * Calls actions depending on the entered command line arguments.
     *
     * @param args the command line arguments
     * @throws IllegalArgumentException
     * @throws IOException
     * @throws NullPointerException
     * @throws org.xml.sax.SAXException
     */
    public static void startupSequence(String[] args) throws IllegalArgumentException, IOException, NullPointerException, SAXException {
        //First we parse args from cmd
        CommandHandler.setupCommands();
        HashMap<Command, ArrayList<String>> usedCommands = CommandHandler.processCmdArguments(args);

        if (usedCommands != null) {
            //Second check that used commands follow set rules
            //if they do decide what to do next
            if (CommandHandler.areCommandsValid(usedCommands)) {
                String output = null;
                if (usedCommands.containsKey(Command.OUTPUT)) {
                    output = usedCommands.get(Command.OUTPUT).get(0);
                }
                if (usedCommands.containsKey((Command.NO_COPY))) {
                    Transformere.setCopyFiles(false);
                }

                //if the only command is help then output help text otherwise help will be ignored
                if (usedCommands.containsKey(Command.HELP) && usedCommands.size() == 1) {
                    System.out.println(String.format("DocBook Archive Manager, version %s.", DocbookArchiveManager.VERSION));
                    System.out.println("Author: Jakub Hrachovec\n");
                    for (Command c : Command.values()) {
                        System.out.println(String.format("%s %s", c.getCommand(), c.getHelpText()));
                    }
                    System.out.println("\nProject site: https://sourceforge.net/projects/docbook-archive/");
                } //set up converting opertation
                else if (usedCommands.containsKey(Command.CONVERT)) {

                    String name = usedCommands.get(Command.CONVERT).get(0);
                    if (!StringHelper.isValidURL(name)) {

                        File f = FileManager.getLocalXmlFile(name, getStartFolder());
                        if (f != null) {
                            Converter.setUserEnteredDbFile(f);
                            if (usedCommands.containsKey(Command.MODE)) {
                                Converter.setMode(Converter.Mode.USER_MODE);
                                System.out.println(String.format("User Mode Engaged. (%s)", Command.MODE.getCommand()));
                            }

                            System.out.println(String.format("Starting conversion of %s to a DocBook ZIP archive.\n", f.getName()));

                            prestartChecks(f, output);
                            //add stylesheets from attributes to the output zip file
                            if (usedCommands.containsKey(Command.ADD_STYLESHEETS)) {
                                for (int i = 0; i < usedCommands.get(Command.ADD_STYLESHEETS).size(); i++) {
                                    String value = usedCommands.get(Command.ADD_STYLESHEETS).get(i);
                                    String isFoString = usedCommands.get(Command.ADD_STYLESHEETS).get(++i);

                                    Stylesheet.IsFormatObject isFo;

                                    if (Boolean.parseBoolean(isFoString)) {
                                        isFo = Stylesheet.IsFormatObject.TRUE;
                                    } else {
                                        isFo = Stylesheet.IsFormatObject.FALSE;
                                    }

                                    if (StringHelper.isValidURL(value)) {
                                        Converter.addStylesheet(new Stylesheet(value, isFo, value, Stylesheet.Type.S));
                                    } else {
                                        File temp = FileManager.getLocalXmlFile(value, getStartFolder());
                                        if (temp != null) {
                                            Converter.processFile(temp, FileManager.getOutputFolder(temp, DocbookFile.Type.XSL.getPath()), null, DocbookFile.Type.XSL, true, Stylesheet.Type.S, isFo);
                                        }
                                    }
                                }
                            }

                            //starts conversion of said XML 
                            startConversion(f);
                        }
                    } else {
                        System.out.println("ERROR: Input XML has to be on local machine.");
                    }
                    //set up transforming operation
                } else if (usedCommands.containsKey(Command.TRANSFORM)) {
                    String name = usedCommands.get(Command.TRANSFORM).get(0);
                    if (!StringHelper.isValidURL(name)) {
                        File f = FileManager.getLocalFile(name, getStartFolder());
                        if (f != null) {

                            prestartChecks(f, output);

                            boolean fo = false;
                            if (usedCommands.containsKey(Command.FO)) {
                                fo = true;
                            }
                            ArrayList<String> params = null;
                            if (usedCommands.containsKey(Command.PARAMS)) {
                                params = usedCommands.get(Command.PARAMS);
                            }
                            if (usedCommands.containsKey(Command.SAXON)) {
                                System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
                            } else {
                                System.setProperty("javax.xml.transform.TransformerFactory", "com.icl.saxon.TransformerFactoryImpl");
                            }

                            String xsl = null;

                            if (usedCommands.containsKey(Command.XSL)) {
                                String temp = usedCommands.get(Command.XSL).get(0);

                                if (FileManager.isStylesheetAtUrl(temp)) {
                                    xsl = temp;
                                } else {
                                    File ff = FileManager.getLocalXmlFile(temp, startFolder);
                                    if (ff != null) {
                                        xsl = ff.getCanonicalPath();
                                    }
                                }
                            }

                            //User entered an xml to be transformed.
                            if (FileManager.sameContentType(f, FileManager.CONTENT_TYPES, false)) {
                                Transformere.startTransformationProcess(f, xsl, false, fo, params, outputFile);
                                //DocbookArchive was entered.
                            } else if (".dar".equals(FileManager.getFileExtension(f))) {
                                Transformere.startTransformationProcess(f, xsl, true, fo, params, outputFile);
                            } else {
                                System.out.println("ERROR: File has to be either Dockbook Archive (.dar) or an XML.");
                            }

                        }
                    } else {
                        System.out.println("ERROR: Input file has to be on local machine.");
                    }
                }

            }

        } else {
            System.out.println("No commands entered. Use " + Command.HELP.getCommand() + " for help.");
            //Exits the program
        }
    }

    /**
     * Deletes temporary folders.
     */
    public static void cleanUp() {
        if (globalOutputFolder != null) {
            FileManager.deleteFile(globalOutputFolder);
        }
//        if (tempFileDownloads != null) {
//            FileManager.deleteFile(tempFileDownloads);
//        }
    }

    private static void startConversion(File file) throws IOException, NullPointerException, SAXException {
        Data.prepareData();
        DomManager.validateXmlFile(DomManager.XSD_FILE, file);
        System.out.println();
        Converter.convert(file, outputFile);
    }

    private static void prestartChecks(File f, String outputFolder) throws IOException {
        createTempFolders(f);
        checkOutputFolder(outputFolder);
    }

    private static void createTempFolders(File f) throws IOException {
        setGlobalNameOfFile(f.getName());
        setGlobalParentFolder(f.getParentFile());
        setGlobalOutputFolder(File.createTempFile("_DAR" + globalNameOfFile, ""));
        globalOutputFolder.delete();
        globalOutputFolder.mkdir();
//        setTempFileDownloads(File.createTempFile("_DAR" + globalNameOfFile + "_downloads", ""));
//        tempFileDownloads.delete();
//        tempFileDownloads.mkdir();
    }

    private static void checkOutputFolder(String outputFolder) {
        if (outputFolder != null) {
            if (!createOutputFolder(outputFolder)) {
                System.out.println(String.format("ERROR: Unable to create all folders for %s.", outputFolder));
                System.out.println(String.format("ERROR: Setting output folder to be same as parent folder of the input file."));
            }
        }
    }

    public static boolean createOutputFolder(String s) {
        File file = FileManager.getAbsoluteFile(s, startFolder);
        boolean temp = false;
        if (file.getParentFile().exists()) {
            temp = true;
            outputFile = file;
        } else if (file.getParentFile().mkdirs()) {
            temp = true;
            outputFile = file;
        }
        return temp;
    }

    /**
     * @return the globalNameOfFile
     */
    public static String getGlobalNameOfFile() {
        return globalNameOfFile;
    }

    /**
     * @param newGlobalNameOfFile
     */
    public static void setGlobalNameOfFile(String newGlobalNameOfFile) {

        globalNameOfFile = newGlobalNameOfFile;
    }

    /**
     * @return the globalParentFolder
     */
    public static File getGlobalParentFolder() {
        return globalParentFolder;
    }

    /**
     * @param newGlobalParentFolder
     */
    public static void setGlobalParentFolder(File newGlobalParentFolder) {
        globalParentFolder = newGlobalParentFolder;
    }

    /**
     * @return the globalOutputFolder
     */
    public static File getGlobalOutputFolder() {
        return globalOutputFolder;
    }

    /**
     * @param newGlobalOutputFolder
     */
    public static void setGlobalOutputFolder(File newGlobalOutputFolder) {
        globalOutputFolder = newGlobalOutputFolder;
    }

    /**
     * @return the tempFileDownloads
     */
    public static File getTempFileDownloads() {
        return tempFileDownloads;
    }

    /**
     * @param newTempFileDownloads
     */
    public static void setTempFileDownloads(File newTempFileDownloads) {
        tempFileDownloads = newTempFileDownloads;
    }

    /**
     * @return the startFolder
     */
    public static File getStartFolder() {
        return startFolder;
    }
}
